﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Sustainalytics.ClientDW.Synchronization.RiskRatingsBenchmarks
{
    public class Histogram<T,TK>
    {

        readonly Dictionary<TK, int[]> histograms= new Dictionary<TK, int[]>();

        readonly Dictionary<TK, int> count = new Dictionary<TK, int>();

        private Histogram()
        {

        }


        public static Histogram<T, TK> Create(ICollection<T> companyCollection, Func<T,TK> key, Func<T,double> scoreSelector, IComparer<double?> scoreComparer, int numberOfBuckets = 101)
        {
            if (companyCollection == null)
                throw new ArgumentNullException(nameof(companyCollection));

            var result = new Histogram<T, TK>();
            TK keyId;
            foreach (var company in companyCollection)
            {
                
                var bin = GetBinByScore(scoreSelector(company), scoreComparer);

                if (key == null)
                {
                    keyId = default(TK);
                }
                else
                {
                    keyId = key(company);
                }

                if (!result.histograms.ContainsKey(keyId))
                {
                    result.histograms.Add(keyId, new int[numberOfBuckets]);
                }

                if (!result.count.ContainsKey(keyId))
                {
                    result.count.Add(keyId, 0);
                }

                result.count[keyId]++;

                result.histograms[keyId][bin]++;
            }

            return result;
        }


        public Tuple<int[],int> GetDataPoints(TK key=default(TK))
        {
            if (key.Equals(default(TK)))
            {
                return new Tuple<int[], int>( histograms.First().Value,count.First().Value);
            }
            return new Tuple<int[], int>(histograms[key], count[key]) ;
        }

        public TK[] GetHistogramsKeys() => histograms.Keys.ToArray();

        static int GetBinByScore(double? score, IComparer<double?> scoreComparer)
        {

            if (scoreComparer.Compare(score, 0) == -1)
            { throw new IndexOutOfRangeException(); }

            if (scoreComparer.Compare(score, 100) == 1)
            { throw new IndexOutOfRangeException(); }


            return (int)Math.Floor(score.GetValueOrDefault());

        }

        public IEnumerable<Tuple<TK,int[],int>> GetHistograms()
        {
            foreach(var kvp in histograms)
            {
                yield return new Tuple<TK, int[], int> (kvp.Key,kvp.Value,count[kvp.Key]);
            }
        }
    }
}
